﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Drawing;
using Kitware.VTK;
using LibPlateAnalysis;
using HCSAnalyzer.Classes.Base_Classes.GUI;
using HCSAnalyzer.Classes.General_Types;
using ImageAnalysis;
using HCSAnalyzer.Classes.Base_Classes;
using HCSAnalyzer.Classes.MetaComponents;
using HCSAnalyzer.Classes.Base_Classes.DataStructures;
using HCSAnalyzer.Classes.Base_Classes.DataAnalysis;
using HCSAnalyzer.Classes.ImageAnalysis._3D_Engine;

namespace HCSAnalyzer.Classes._3D
{
    public class cListGeometric3DObject : List<cGeometric3DObject>
    {
        public object Tag;
        public string Name;

        public void AddObject(cGeometric3DObject ObjectToBeAdded)
        {
            ObjectToBeAdded.ParentTag = this;
            this.Add(ObjectToBeAdded);
        }

        public ToolStripMenuItem GetContextMenu()
        {

            if (this.Count == 0) return null;

            ToolStripMenuItem SpecificContextMenu = new ToolStripMenuItem("List " + this.Count + " 3D_Objects");

            ToolStripMenuItem ToolStripMenuItem_Opacity = new ToolStripMenuItem("Opacity");
            ToolStripMenuItem_Opacity.Click += new System.EventHandler(this.ToolStripMenuItem_Opacity);
            SpecificContextMenu.DropDownItems.Add(ToolStripMenuItem_Opacity);


            ToolStripMenuItem ToolStripMenuItem_Color = new ToolStripMenuItem("Color");
            ToolStripMenuItem_Color.Click += new System.EventHandler(this.ToolStripMenuItem_Color);
            SpecificContextMenu.DropDownItems.Add(ToolStripMenuItem_Color);

            ToolStripMenuItem ToolStripMenuItem_Scale = new ToolStripMenuItem("Scale");
            ToolStripMenuItem_Scale.Click += new System.EventHandler(this.ToolStripMenuItem_Scale);
            SpecificContextMenu.DropDownItems.Add(ToolStripMenuItem_Scale);



            ToolStripMenuItem ToolStripMenuItem_BuildDensityMap = new ToolStripMenuItem("Build Density Map");
            ToolStripMenuItem_BuildDensityMap.Click += new System.EventHandler(this.ToolStripMenuItem_BuildDensityMap);
            SpecificContextMenu.DropDownItems.Add(ToolStripMenuItem_BuildDensityMap);


            if (this.Tag != null)
            {
                if (this.Tag.GetType() == typeof(cListWells))
                {
                    SpecificContextMenu.DropDownItems.Add(((cListWells)this.Tag).GetContextMenu());
                }
            }


            return SpecificContextMenu;

        }

        private void ToolStripMenuItem_BuildDensityMap(object sender, EventArgs e)
        {
            cTableFrom3DObjects MyTable = new cTableFrom3DObjects();
            MyTable.SetInputData(this);
            MyTable.Run();

            //cDisplayExtendedTable DET = new cDisplayExtendedTable();
            //DET.SetInputData(MyTable.GetOutPut());
            //DET.Run();

            cBuildDensityMap BDM = new cBuildDensityMap();
            BDM.SetInputData(new cListExtendedTable(MyTable.GetOutPut()));
            BDM.ListProperties.FindByName("Kernel size").SetNewValue((int)10);
            BDM.ListProperties.FindByName("Kernel size").IsGUIforValue = true;

            BDM.ListProperties.FindByName("Image width").SetNewValue((int)256);
            BDM.ListProperties.FindByName("Image width").IsGUIforValue = true;
            BDM.ListProperties.FindByName("Image height").SetNewValue((int)256);
            BDM.ListProperties.FindByName("Image height").IsGUIforValue = true;
            BDM.ListProperties.FindByName("Image depth").SetNewValue((int)256);
            BDM.ListProperties.FindByName("Image depth").IsGUIforValue = true;

            BDM.Run();

           // cVolumeRendering3D Vol = new cVolumeRendering3D(BDM.GetOutPut().SingleChannelImage[0],new cPoint3D(0,0,0), null);
            

            cImageViewer IV = new cImageViewer();
            //  IV.AssociatedImage
            IV.SetImage(BDM.GetOutPut());
            IV.Display();
        }

        private void ToolStripMenuItem_Color(object sender, EventArgs e)
        {
            ColorDialog ColorPicker = new ColorDialog();
            if (ColorPicker.ShowDialog() != DialogResult.OK) return;
            SetColor(ColorPicker.Color);
        }
        
        private void ToolStripMenuItem_Opacity(object sender, EventArgs e)
        {
            FormForSingleSlider SliderForOpacity = new FormForSingleSlider("Object Opacity");
            SliderForOpacity.numericUpDown.Value = (decimal)(100.0);

            if (SliderForOpacity.ShowDialog() != DialogResult.OK) return;


            //Obj.SetOpacity((double)SliderForOpacity.numericUpDown.Value / 100.0);
            SetOpacity((double)SliderForOpacity.numericUpDown.Value / 100.0);
        }

        private void ToolStripMenuItem_Scale(object sender, EventArgs e)
        {
            FormForSingleSlider SliderForScale = new FormForSingleSlider("Object Scale");
            SliderForScale.numericUpDown.Maximum = 1000;
            SliderForScale.numericUpDown.Value = (decimal)(1000);

            if (SliderForScale.ShowDialog() != DialogResult.OK) return;


            //Obj.SetOpacity((double)SliderForOpacity.numericUpDown.Value / 100.0);
            SetScale((double)SliderForScale.numericUpDown.Value / 100.0);
        }

        public void SetScale(double Scale)
        {
            foreach (var item in this)
                item.SetScale(Scale);
        }

        public void SetOpacity(double Opacity)
        {
            foreach (var item in this)
                item.SetOpacity(Opacity);
        }

        public void SetColor(Color Colour)
        {
            foreach (var item in this)
                item.SetColor(Colour);
        }
        
    }


    public class cGeometric3DObject : cObject3D
    {
        protected vtkFollower TextActorFollower = null;
        public cInteractive3DObject AssociatedObject = null;
        public vtkAlgorithmOutput AlgoOutPut = null;
        public bool IsStayInFrontOfCamera = false;
        public object ParentTag = null;

        public cGeometric3DObject()
        {
            vtk_Actor.SetPickable(1);
            ObjectType = "Geometrical";
        }

        public int GetHashCode()
        {
            return -1;
        }

        public cGeometric3DObject(vtkActor CurrentActor)
        {
            vtk_Actor = CurrentActor;
        }

        public cGeometric3DObject(vtkActor CurrentActor, Color NewColor)
        {
            CurrentActor.GetProperty().SetColor(NewColor.R / 255.0, NewColor.G / 255.0, NewColor.B / 255.0);
            vtk_Actor = CurrentActor;
            vtk_Actor.SetPickable(1);
            ObjectType = "Geometrical";
        }
    }

    /// <summary>
    /// 3D sphere Object
    /// </summary>
    public class c3DSphere : cGeometric3DObject
    {
        public double Radius;
        public vtkSphereSource sphere;

        private void CreateSphere(cPoint3D Center, double Radius, Color Colour, int Precision)
        {
            Position = new cPoint3D(Center.X, Center.Y, Center.Z);

            this.Radius = Radius;
            this.Colour = Colour;

            sphere = vtkSphereSource.New();
            sphere.SetThetaResolution(Precision);
            sphere.SetPhiResolution(Precision);
            sphere.SetRadius(Radius);
            vtk_PolyDataMapper = vtkPolyDataMapper.New();
            vtk_PolyDataMapper.SetInputConnection(sphere.GetOutputPort());

            CreateVTK3DObject(2);
        }

        public c3DSphere(cPoint3D Center, double Radius, Color Colour)
        {
            CreateSphere(Center, Radius, Colour, 16);
        }

        public c3DSphere(cPoint3D Center, double Radius, Color Colour, int Precision)
        {
            CreateSphere(Center, Radius, Colour, Precision);
        }

        public c3DSphere(cPoint3D Center, double Radius)
        {
            CreateSphere(Center, Radius, Color.Red, 16);
        }
    }

    public class c3DArrow : cGeometric3DObject
    {
        public double Scale;
        public vtkArrowSource Arrow;


        private void CreateArrow(cPoint3D Position, double Scale, Color Colour)
        {
            base.Position = new cPoint3D(Position.X, Position.Y, Position.Z);

            this.Scale = Scale;
            base.Colour = Colour;

            Arrow = vtkArrowSource.New();


            vtk_PolyDataMapper = vtkPolyDataMapper.New();
            vtk_PolyDataMapper.SetInputConnection(Arrow.GetOutputPort());


            // ArrowActor = vtkActor.New();
            // vtkPolyDataMapper ArrowMapper = vtkPolyDataMapper.New();
            // ArrowMapper.SetInputConnection(ArrowSource.GetOutputPort());
            //  ArrowActor.SetMapper(ArrowMapper);

            // ArrowActor.SetPosition(Position.X - 6, Position.Y - 0, Position.Z - 6);
            // ArrowActor.RotateY(-45);

            // ArrowActor.SetScale(scale);
            //   ArrowActor.SetPickable(0);
            //    Color C = Color.MediumPurple;

            //    ArrowActor.GetProperty().SetColor(Colour.R / 255.0, Colour.G / 255.0, Colour.G / 255.0);

            //sphere.SetThetaResolution(Precision);
            //sphere.SetPhiResolution(Precision);
            //sphere.SetRadius(Radius);
            //vtk_PolyDataMapper = vtkPolyDataMapper.New();
            //vtk_PolyDataMapper.SetInputConnection(sphere.GetOutputPort());

            CreateVTK3DObject(1);

            base.vtk_Actor.RotateY(-45);
            base.vtk_Actor.SetScale(Scale);
            //  base.vtk_Actor.SetPosition(Position.X, Position.Y, Position.Z);
            //   base.vtk_Actor.GetProperty().SetColor(Colour.R / 255.0, Colour.G / 255.0, Colour.G / 255.0);
        }

        public c3DArrow(cPoint3D Position, double Scale, Color Colour)
        {
            CreateArrow(Position, Scale, Colour);
        }

        public c3DArrow(cPoint3D Position, double Scale)
        {
            CreateArrow(Position, Scale, Color.White);
        }

        public c3DArrow(cPoint3D Start, cPoint3D End)
        {
            BuildArrow(Start, End, Color.White);
        }

        public c3DArrow(cPoint3D Start, cPoint3D End, Color Colour)
        {
            BuildArrow(Start, End, Colour);
        }

        void BuildArrow(cPoint3D Start, cPoint3D End, Color Colour)
        {

            base.Position = new cPoint3D(Start.X, Start.Y, Start.Z);

            cPoint3D normalizedX = new cPoint3D(End.X - Start.X, End.Y - Start.Y, End.Z - Start.Z);
            double Norm = Math.Sqrt(normalizedX.X * normalizedX.X + normalizedX.Y * normalizedX.Y + normalizedX.Z * normalizedX.Z);

            normalizedX.X /= Norm;
            normalizedX.Y /= Norm;
            normalizedX.Z /= Norm;

            double[] arbitrary = new double[3];
            arbitrary[0] = -0.6;
            arbitrary[1] = 0.8;
            arbitrary[2] = 0.9;
            double NormZ = Math.Sqrt(arbitrary[0] * arbitrary[0] + arbitrary[1] * arbitrary[1] + arbitrary[2] * arbitrary[2]);

            arbitrary[0] /= NormZ;
            arbitrary[1] /= NormZ;
            arbitrary[2] /= NormZ;

            cPoint3D normalizedZ = new cPoint3D(normalizedX.Y * arbitrary[2] - normalizedX.Z * arbitrary[1],
                                                normalizedX.Z * arbitrary[0] - normalizedX.X * arbitrary[2],
                                                normalizedX.X * arbitrary[1] - normalizedX.Y * arbitrary[0]);

            cPoint3D normalizedY = new cPoint3D(normalizedZ.Y * normalizedX.Z - normalizedZ.Z * normalizedX.Y,
                                                normalizedZ.Z * normalizedX.X - normalizedZ.X * normalizedX.Z,
                                                normalizedZ.X * normalizedX.Y - normalizedZ.Y * normalizedX.X);

            vtkMatrix4x4 matrix = vtkMatrix4x4.New();
            matrix.Identity();
            matrix.SetElement(0, 0, normalizedX.X);
            matrix.SetElement(0, 1, normalizedY.X);
            matrix.SetElement(0, 2, normalizedZ.X);

            matrix.SetElement(1, 0, normalizedX.Y);
            matrix.SetElement(1, 1, normalizedY.Y);
            matrix.SetElement(1, 2, normalizedZ.Y);

            matrix.SetElement(2, 0, normalizedX.Z);
            matrix.SetElement(2, 1, normalizedY.Z);
            matrix.SetElement(2, 2, normalizedZ.Z);

            // Apply the transforms
            vtkTransform transform = vtkTransform.New();
            transform.Translate(Start.X, Start.Y, Start.Z);
            transform.Concatenate(matrix);
            transform.Scale(Norm, Norm, Norm);

            // Transform the polydata
            vtkTransformPolyDataFilter transformPD = vtkTransformPolyDataFilter.New();
            transformPD.SetTransform(transform);

            Arrow = vtkArrowSource.New();

            transformPD.SetInputConnection(Arrow.GetOutputPort());

            //this.Scale = Scale;
            base.Colour = Colour;
            Scale = 1;

            double Tip = Arrow.GetTipLength();
            Arrow.SetTipLength(0.0005 / Norm);
            double Rad = Arrow.GetTipRadius();
            Arrow.SetTipRadius(0.02 / Norm);
            double Res = Arrow.GetTipResolution();
            Arrow.SetTipResolution(20);
            double SRad = Arrow.GetShaftRadius();
            Arrow.SetShaftRadius(0.005 / Norm);
            Arrow.SetShaftResolution(20);

            vtk_PolyDataMapper = vtkPolyDataMapper.New();
            vtk_PolyDataMapper.SetInputConnection(transformPD.GetOutputPort());

            CreateVTK3DObject(1);

            base.vtk_Actor.SetScale(Scale);
        }

    }


    public class c3DDRC : cGeometric3DObject
    {
        public vtkParametricSpline Spline;

        private void Create3DDRC(cDRC DRCToDraw, cDRC_Region AssociatedRegion, Color Color, double Min, double Max)
        {
            if (DRCToDraw.ResultFit == null) return;

            Position = new cPoint3D(AssociatedRegion.PosXMin + 0.5, AssociatedRegion.PosYMin + 0.2, 0);
            this.Colour = Color;
            vtkPoints points = vtkPoints.New();

            vtkUnsignedCharArray colors = vtkUnsignedCharArray.New();
            colors.SetName("Colors");
            colors.SetNumberOfComponents(3);
            colors.SetNumberOfTuples(AssociatedRegion.NumConcentrations);

            for (int i = 0; i < AssociatedRegion.NumConcentrations; i++)
            {
                if (i >= DRCToDraw.ResultFit.Y_Estimated.Count) continue;
                double PosZ = 8 - ((DRCToDraw.ResultFit.GetNormalizedY_Estimated()[i]) * 8);

                points.InsertPoint(i, i, 0, PosZ);
                colors.InsertTuple3(i / AssociatedRegion.NumConcentrations, i / AssociatedRegion.NumConcentrations, 255, i / AssociatedRegion.NumConcentrations);
            }

            Spline = vtkParametricSpline.New();
            Spline.SetPoints(points);
            Spline.ClosedOff();

            vtkParametricFunctionSource SplineSource = vtkParametricFunctionSource.New();
            SplineSource.SetParametricFunction(Spline);

            //     SplineSource.GetPolyDataInput(0).GetPointData().AddArray(colors);

            vtkLinearExtrusionFilter extrude = vtkLinearExtrusionFilter.New();
            extrude.SetInputConnection(SplineSource.GetOutputPort());

            //extrude.GetPolyDataInput(0).GetPointData().AddArray(colors);
            extrude.SetScaleFactor(AssociatedRegion.NumReplicate - 0.2);
            //extrude.SetExtrusionTypeToNormalExtrusion();

            extrude.SetExtrusionTypeToVectorExtrusion();
            extrude.SetVector(0, 1, 0);

            vtk_PolyDataMapper = vtkPolyDataMapper.New();
            vtk_PolyDataMapper.SetInputConnection(extrude.GetOutputPort()/*SplineSource.GetOutputPort()*/);
            vtk_PolyDataMapper.GetInput().GetPointData().AddArray(colors);
            vtk_PolyDataMapper.ScalarVisibilityOn();
            vtk_PolyDataMapper.SetScalarModeToUsePointFieldData();
            vtk_PolyDataMapper.SelectColorArray("Colors");

            CreateVTK3DObject(3);
        }

        public c3DDRC(cDRC DRCToDraw, cDRC_Region AssociatedRegion, Color Color, double Min, double Max)
        {
            Create3DDRC(DRCToDraw, AssociatedRegion, Color, Min, Max);
        }

        public c3DDRC(cDRC DRCToDraw, cDRC_Region AssociatedRegion, double Min, double Max)
        {
            Create3DDRC(DRCToDraw, AssociatedRegion, Color.White, Min, Max);
        }
    }

    public class c3DThinPlate : cGeometric3DObject
    {



        // double regularization = 0.0;
        double bending_energy = 0.0;

        //List<Vector3> control_points = new List<Vector3>();

        /// <summary> Thin-Plate-Spline base function
        /// </summary>
        /// <param name="r">the function parameter</param>
        /// <returns></returns>
        public double tps_base_func(double r)
        {
            if (r == 0.0)
                return 0.0;
            else
                return r * r * Math.Log(r);
        }

        /// <summary>
        /// Compute the Thin Plate Spline of the image, return a 2D tab
        /// </summary>
        /// <param name="control_points">Control points  </param>    
        /// <param name="input">Input image to get the dim xy</param>
        public double[,] calc_tps(List<cPoint3D> control_points, cDRC_Region AssociatedRegion, double Regularization)
        {

            int p = control_points.Count;
            if (p < 3) return null;
            double[,] grid = new double[AssociatedRegion.SizeX, AssociatedRegion.SizeY];
            Matrix mtx_l = new Matrix(p + 3, p + 3);
            Matrix mtx_v = new Matrix(p + 3, 1);
            Matrix mtx_orig_k = new Matrix(p, p);
            double a = 0.0;
            for (int i = 0; i < p; ++i)
            {
                for (int j = i + 1; j < p; ++j)
                {
                    cPoint3D pt_i = new cPoint3D(control_points[i].X, control_points[i].Y, control_points[i].Z);
                    cPoint3D pt_j = new cPoint3D(control_points[j].X, control_points[j].Y, control_points[j].Z);

                    pt_i.Y = pt_j.Y = 0;

                    //double elen = Math.Sqrt((pt_i.X - pt_j.X) * (pt_i.X - pt_j.X) + (pt_i.Z - pt_j.Z) * (pt_i.Z - pt_j.Z));
                    double elen = pt_i.DistTo(pt_j);
                    mtx_l[i, j] = mtx_l[j, i] = mtx_orig_k[i, j] = mtx_orig_k[j, i] = tps_base_func(elen);
                    a += elen * 2; // same for upper & lower tri
                }
            }
            a /= (double)(p * p);
            //regularization = 0.3f;
            //Fill the rest of L
            for (int i = 0; i < p; ++i)
            {
                //diagonal: reqularization parameters (lambda * a^2)

                mtx_l[i, i] = mtx_orig_k[i, i] = Regularization * (a * a);



                // P (p x 3, upper right)
                mtx_l[i, p + 0] = 1.0;
                mtx_l[i, p + 1] = control_points[i].X;
                mtx_l[i, p + 2] = control_points[i].Z;

                // P transposed (3 x p, bottom left)
                mtx_l[p + 0, i] = 1.0;
                mtx_l[p + 1, i] = control_points[i].X;
                mtx_l[p + 2, i] = control_points[i].Z;
            }
            // O (3 x 3, lower right)
            for (int i = p; i < p + 3; ++i)
                for (int j = p; j < p + 3; ++j)
                    mtx_l[i, j] = 0.0;


            // Fill the right hand vector V
            for (int i = 0; i < p; ++i)
                mtx_v[i, 0] = control_points[i].Y;

            mtx_v[p + 0, 0] = mtx_v[p + 1, 0] = mtx_v[p + 2, 0] = 0.0;
            // Solve the linear system "inplace" 
            Matrix mtx_v_res = new Matrix(p + 3, 1);

            LuDecomposition ty = new LuDecomposition(mtx_l);



            mtx_v_res = ty.Solve(mtx_v);
            if (mtx_v_res == null)
            {
                return null;
            }


            // Interpolate grid heights
            for (int x = 0; x < AssociatedRegion.SizeX; ++x)
            {
                for (int z = 0; z < AssociatedRegion.SizeY; ++z)
                {

                    //float x = 0f; float z = 0.5f;
                    double h = mtx_v_res[p + 0, 0] + mtx_v_res[p + 1, 0] * (float)x / (float)AssociatedRegion.SizeX + mtx_v_res[p + 2, 0] * (float)z / (float)AssociatedRegion.SizeY;
                    //double h = mtx_v[p + 0, 0] + mtx_v[p + 1, 0] * (float)x + mtx_v[p + 2, 0] * (float)z ;
                    cPoint3D pt_ia;
                    cPoint3D pt_cur = new cPoint3D((float)x / (float)AssociatedRegion.SizeX, 0, (float)z / (float)AssociatedRegion.SizeY);
                    //Vector3 pt_cur = new Vector3((float)x , 0, (float)z);
                    for (int i = 0; i < p; ++i)
                    {
                        pt_ia = control_points[i];
                        pt_ia.Y = 0;
                        h += mtx_v_res[i, 0] * tps_base_func(pt_ia.DistTo(pt_cur));
                    }

                    grid[x, z] = h;
                }
            }
            // Calc bending energy
            Matrix w = new Matrix(p, 1);
            for (int i = 0; i < p; ++i)
                w[i, 0] = mtx_v_res[i, 0];

            Matrix be;

            be = Matrix.Multiply(Matrix.Multiply(w.Transpose(), mtx_orig_k), w);
            bending_energy = be[0, 0];

            Console.WriteLine("be= " + be[0, 0]);
            return grid;


        }

        private void Create(cDRC_Region AssociatedRegion, Color Color, double Regularization)
        {
            Position = new cPoint3D(AssociatedRegion.PosXMin + 1, AssociatedRegion.PosYMin + 0.7, 0);

            List<cPoint3D> ListPtSigma = new List<cPoint3D>();

            double GlobalMin = double.MaxValue;
            double GlobalMax = double.MinValue;
            for (int j = 0; j < AssociatedRegion.SizeY; j++)
                for (int i = 0; i < AssociatedRegion.SizeX; i++)
                {
                    cWell TmpWell = AssociatedRegion.GetListWells()[j][i];
                    if (TmpWell == null) continue;
                    double PosZ = TmpWell.ListSignatures[TmpWell.AssociatedPlate.ParentScreening.ListDescriptors.CurrentSelectedDescriptorIdx].GetValue();
                    if (PosZ >= GlobalMax) GlobalMax = PosZ;
                    if (PosZ <= GlobalMin) GlobalMin = PosZ;

                    ListPtSigma.Add(new cPoint3D(i / (double)AssociatedRegion.SizeX, PosZ, j / (double)AssociatedRegion.SizeY));
                }

            if (GlobalMax == GlobalMin) return;



            double[,] ResultThinPlate = calc_tps(ListPtSigma, AssociatedRegion, Regularization);

            if (ResultThinPlate == null)
            {
                // MessageBox.Show("Error in computing the associated thinplate !", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            //  Position = new cPoint3D(0, 0, 0);
            this.Colour = Color;
            vtkPoints points = vtkPoints.New();
            // vtkPoints points0 = vtkPoints.New();

            //vtkUnsignedCharArray colors = vtkUnsignedCharArray.New();
            //colors.SetName("Colors");
            //colors.SetNumberOfComponents(3);
            //colors.SetNumberOfTuples(AssociatedRegion.SizeX * AssociatedRegion.SizeY);




            int Idx = 0;
            for (int j = 0; j < AssociatedRegion.SizeY; j++)
                for (int i = 0; i < AssociatedRegion.SizeX; i++)
                {
                    cWell TmpWell = AssociatedRegion.GetListWells()[j][i];

                    double PosZ = 8 - ((ResultThinPlate[i, j] - GlobalMin) / (GlobalMax - GlobalMin)) * 8;


                    //points.InsertPoint(Idx,TmpWell.GetPosX(), TmpWell.GetPosY(), PosZ);

                    //  points.InsertPoint(Idx, TmpWell.GetPosX(), TmpWell.GetPosY(), 0);
                    points.InsertPoint(Idx++, i, j, PosZ);
                    //  colors.InsertTuple3(Idx++, 1, 1, 1);

                }

            vtkPolyData profile = vtkPolyData.New();
            profile.SetPoints(points);

            vtkDelaunay2D del = vtkDelaunay2D.New();
            del.SetInput(profile);
            del.SetTolerance(0.001);



            vtkButterflySubdivisionFilter subdivisionFilter = vtkButterflySubdivisionFilter.New();
            subdivisionFilter.SetInput(del.GetOutput());
            subdivisionFilter.SetNumberOfSubdivisions(2);
            subdivisionFilter.Update();






            vtk_PolyDataMapper = vtkPolyDataMapper.New();

            AlgoOutPut = subdivisionFilter.GetOutputPort();

            vtk_PolyDataMapper.SetInputConnection(AlgoOutPut);
            // vtk_PolyDataMapper.GetInput().GetPointData().AddArray(colors);
            // vtk_PolyDataMapper.ScalarVisibilityOn();
            // vtk_PolyDataMapper.SetScalarModeToUsePointFieldData();
            // vtk_PolyDataMapper.SelectColorArray("Colors");





            //         vtkLinearExtrusionFilter  extrude = vtkLinearExtrusionFilter.New();
            //         extrude.SetInput(cutter.GetOutput());
            //extrude.SetScaleFactor(1);
            //extrude.SetExtrusionTypeToNormalExtrusion();
            //extrude.SetVector(1, 1, 1);

            //vtkRotationalExtrusionFilter extrude = vtkRotationalExtrusionFilter.New();
            //extrude.SetInput(cutter.GetOutput());
            //extrude.SetResolution(60);
            //extrude.Update();



            //vtk_PolyDataMapper.SetInputConnection(tubeFilter.GetOutputPort());




            CreateVTK3DObject(3);

            SetColor(Color);
            // SetOpacity(1);
            SetToSurface();
        }

        public c3DThinPlate(cDRC_Region AssociatedRegion, Color Color, double Regularization)
        {
            Create(AssociatedRegion, Color, Regularization);
        }

        public c3DThinPlate(cDRC_Region AssociatedRegion, double Regularization)
        {
            Create(AssociatedRegion, Color.White, Regularization);
        }
    }

    /// <summary>
    /// 2D Delaunay mesh
    /// </summary>
    public class c2DDelaunay : cGeometric3DObject
    {
        private void CreateDelaunay(List<cPoint3D> ListPts, Color Colour, bool IsWire)
        {
            Position = new cPoint3D(0, 0, 0);
            this.Colour = Colour;
            vtkPoints ListCentroid = vtkPoints.New();

            for (int i = 0; i < ListPts.Count; i++)
                ListCentroid.InsertPoint(i, ListPts[i].X, ListPts[i].Y, ListPts[i].Z);

            vtkPolyData profile = vtkPolyData.New();
            profile.SetPoints(ListCentroid);

            vtkDelaunay2D del = vtkDelaunay2D.New();
            del.SetInput(profile);
            del.SetTolerance(0.001);

            vtk_PolyDataMapper = vtkPolyDataMapper.New();
            vtk_PolyDataMapper.SetInputConnection(del.GetOutputPort());

            CreateVTK3DObject(0);
            if (IsWire) SetToWireFrame();
            else SetToSurface();
        }

        public c2DDelaunay(List<cPoint3D> ListPts, Color Colour, bool IsWire)
        {
            CreateDelaunay(ListPts, Colour, IsWire);
        }

        public c2DDelaunay(List<cPoint3D> ListPts, bool IsWire)
        {
            CreateDelaunay(ListPts, Color.PapayaWhip, IsWire);
        }
    }

    /// <summary>
    /// 3D Line Object
    /// </summary>
    public class c3DLine : cGeometric3DObject
    {
        public vtkLineSource Line;
        private cPoint3D Point1;
        private cPoint3D Point2;

        private void CreateLine(cPoint3D Point1, cPoint3D Point2, Color Colour)
        {
            Position = new cPoint3D(Point1.X, Point1.Y, Point1.Z);

            Position = new cPoint3D(0, 0, 0);

            this.Colour = Colour;
            Line = vtkLineSource.New();

            this.Point1 = new cPoint3D(Point1.X, Point1.Y, Point1.Z);
            this.Point2 = new cPoint3D(Point2.X, Point2.Y, Point2.Z);

            Line.SetPoint1(Point1.X, Point1.Y, Point1.Z);
            Line.SetPoint2(Point2.X, Point2.Y, Point2.Z);


            vtk_PolyDataMapper = vtkPolyDataMapper.New();
            vtk_PolyDataMapper.SetInputConnection(Line.GetOutputPort());


            CreateVTK3DObject(0);
        }

        public c3DLine(cPoint3D Point1, cPoint3D Point2, Color Colour)
        {
            CreateLine(Point1, Point2, Colour);
        }

        public c3DLine(cPoint3D Point1, cPoint3D Point2)
        {
            CreateLine(Point1, Point2, Color.White);
        }

        public void DisplayLenght(c3DWorld CurrentWorld, double scale)
        {
            vtkFollower TextActor = vtkFollower.New();
            vtkPolyDataMapper TextMapper = vtkPolyDataMapper.New();
            vtkVectorText TextVTK = vtkVectorText.New();


            double Dist = Point1.DistTo(Point2);

            TextVTK.SetText(Dist.ToString("N2"));
            TextMapper.SetInputConnection(TextVTK.GetOutputPort());
            TextActor.SetMapper(TextMapper);
            TextActor.SetPosition(this.GetActor().GetCenter()[0], this.GetActor().GetCenter()[1], this.GetActor().GetCenter()[2]);
            TextActor.SetPickable(0);
            TextActor.SetScale(scale);

            CurrentWorld.ren1.AddActor(TextActor);
            TextActor.SetCamera(CurrentWorld.ren1.GetActiveCamera());

        }
    }

    /// <summary>
    /// 3D Line Object
    /// </summary>
    public class c3DText : cGeometric3DObject
    {
        // public vtkLineSource Line;
        private cPoint3D Point1;
        // private cPoint3D Point2;

        //private void CreateLine(cPoint3D Point1, cPoint3D Point2, Color Colour)
        //{
        //    Position = new cPoint3D(Point1.X, Point1.Y, Point1.Z);

        //    Position = new cPoint3D(0, 0, 0);

        //    this.Colour = Colour;
        //    Line = vtkLineSource.New();

        //    this.Point1 = new cPoint3D(Point1.X, Point1.Y, Point1.Z);
        //    this.Point2 = new cPoint3D(Point2.X, Point2.Y, Point2.Z);

        //    Line.SetPoint1(Point1.X, Point1.Y, Point1.Z);
        //    Line.SetPoint2(Point2.X, Point2.Y, Point2.Z);


        //    vtk_PolyDataMapper = vtkPolyDataMapper.New();
        //    vtk_PolyDataMapper.SetInputConnection(Line.GetOutputPort());


        //    CreateVTK3DObject(0);
        //}

        public c3DText(string TextToDisplay, cPoint3D Position, Color Colour, double Scale)
        {
            TextActorFollower = vtkFollower.New();
            vtkPolyDataMapper TextMapper = vtkPolyDataMapper.New();
            vtkVectorText TextVTK = vtkVectorText.New();

            TextVTK.SetText(TextToDisplay);
            TextMapper.SetInputConnection(TextVTK.GetOutputPort());
            TextActorFollower.SetMapper(TextMapper);
            TextActorFollower.SetPosition(Position.X, Position.Y, Position.Z);
            TextActorFollower.SetPickable(0);
            TextActorFollower.SetScale(Scale);
            TextActorFollower.GetProperty().SetColor(Colour.R / 255.0, Colour.G / 255.0, Colour.B / 255.0);
            TextActorFollower.GetProperty().SetAmbient(1);


            base.Position = new cPoint3D(Position.X, Position.Y, Position.Z);
            base.Colour = Colour;

            vtk_PolyDataMapper = vtkPolyDataMapper.New();
            vtk_PolyDataMapper.SetInputConnection(TextVTK.GetOutputPort());



            //  CurrentWorld.ren1.AddActor(TextActor);
            //  TextActorFollower.SetCamera(CurrentWorld.ren1.GetActiveCamera());

        }

        public c3DText(c3DWorld CurrentWorld, string TextToDisplay, cPoint3D Position, Color Colour, double Scale)
        {
            // CreateLine(Point1, Point2, Colour);

            vtkFollower TextActor = vtkFollower.New();
            vtkPolyDataMapper TextMapper = vtkPolyDataMapper.New();
            vtkVectorText TextVTK = vtkVectorText.New();


            //  double Dist = Point1.DistTo(Point2);

            TextVTK.SetText(TextToDisplay);
            TextMapper.SetInputConnection(TextVTK.GetOutputPort());
            TextActor.SetMapper(TextMapper);
            TextActor.SetPosition(Position.X, Position.Y, Position.Z);
            TextActor.SetPickable(0);
            TextActor.SetScale(Scale);
            TextActor.GetProperty().SetColor(Colour.R / 255.0, Colour.G / 255.0, Colour.B / 255.0);
            TextActor.GetProperty().SetAmbient(1);

            CurrentWorld.ren1.AddActor(TextActor);
            TextActor.SetCamera(CurrentWorld.ren1.GetActiveCamera());

        }


        public c3DText(c3DNewWorld CurrentWorld, string TextToDisplay, cPoint3D Position, Color Colour, double Scale)
        {
            vtkFollower TextActor = vtkFollower.New();
            vtkPolyDataMapper TextMapper = vtkPolyDataMapper.New();
            vtkVectorText TextVTK = vtkVectorText.New();

            TextVTK.SetText(TextToDisplay);
            TextMapper.SetInputConnection(TextVTK.GetOutputPort());
            TextActor.SetMapper(TextMapper);
            TextActor.SetPickable(0);
            //TextActor.GetProperty().SetAmbient(1);

            this.Position = new cPoint3D(Position);
            this.Colour = Colour;
           
            TextActor.SetCamera(CurrentWorld.Vtk_CameraView);
            TextActor.SetPosition(Position.X, Position.Y, Position.Z);


            vtk_PolyDataMapper = vtkPolyDataMapper.New();
            vtk_PolyDataMapper.SetInputConnection(TextVTK.GetOutputPort());

         //   CreateVTK3DObject(1);
            base.vtk_Actor = TextActor;
            base.vtk_PolyDataMapper = TextMapper;

            base.vtk_Actor.SetScale(Scale);
        }
    }

    /// <summary>
    /// 3D cube object
    /// </summary>
    public class c3DCube : cGeometric3DObject
    {
        public vtkCubeSource BoundingBox;

        public void Create(cPoint3D MinPt, cPoint3D MaxPt, Color Colour)
        {
            Position = new cPoint3D(0, 0, 0);

            this.Colour = Colour;
            BoundingBox = vtkCubeSource.New();
            BoundingBox.SetBounds(MinPt.X, MaxPt.X, MinPt.Y, MaxPt.Y, MinPt.Z, MaxPt.Z);

            vtk_PolyDataMapper = vtkPolyDataMapper.New();
            vtk_PolyDataMapper.SetInputConnection(BoundingBox.GetOutputPort());

            CreateVTK3DObject(0);
        }
    }

    /// <summary>
    /// 3D plane object
    /// </summary>
    public class c3DPlane : cGeometric3DObject
    {
        public vtkPlaneSource Plane;

        private void CreatePlane(cPoint3D Axis1, cPoint3D Axis2, cPoint3D Origin, Color Colour)
        {
            Position = new cPoint3D(Origin.X, Origin.Y, Origin.Z);

            this.Colour = Colour;
            Plane = vtkPlaneSource.New();
            Plane.SetPoint1(Axis1.X, Axis1.Y, Axis1.Z);
            Plane.SetPoint2(Axis2.X, Axis2.Y, Axis2.Z);
            Plane.SetOrigin(0, 0, 0);
            Plane.SetXResolution(1);
            Plane.SetYResolution(1);

            vtk_PolyDataMapper = vtkPolyDataMapper.New();
            vtk_PolyDataMapper.SetInputConnection(Plane.GetOutputPort());

            CreateVTK3DObject(0);
        }

        public c3DPlane(cPoint3D Point1, cPoint3D Point2, cPoint3D Origin, Color Colour)
        {
            CreatePlane(Point1, Point2, Origin, Colour);
        }

        public c3DPlane(cPoint3D Point1, cPoint3D Point2, cPoint3D Origin)
        {
            CreatePlane(Point1, Point2, Origin, Color.White);
        }
    }
}
